﻿//"The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License at
//http://www.mozilla.org/MPL/

//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//License for the specific language governing rights and limitations
//under the License.

//The Original Code is TSharp.

//The Initial Developer of the Original Code is Mar3ek (http://mar3ek.wordpress.com).
//Portions created by Mar3ek are Copyright (C) 2010
//Mar3ek (http://mar3ek.wordpress.com). All Rights Reserved.

//Contributor(s): ______________________________________.

//Alternatively, the contents of this file may be used under the terms
//of the _____ license (the  "[___] License"), in which case the
//provisions of [______] License are applicable instead of those
//above.  If you wish to allow use of your version of this file only
//under the terms of the [____] License and not to allow others to use
//your version of this file under the MPL, indicate your decision by
//deleting  the provisions above and replace  them with the notice and
//other provisions required by the [___] License.  If you do not delete
//the provisions above, a recipient may use your version of this file
//under either the MPL or the [___] License."

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace TSharp
{
    public partial class Twitter
    {
        #region Direct Messages

        #region GetDirectMessages
        /// <summary>
        /// Returns the 20 most recent direct messages sent to the authenticating user.
        /// </summary>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetDirectMessages()
        {
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages.xml",
                                        true);

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            var col = new Collection<DirectMessage>(doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            return col;
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the <i>count</i> most recent direct messages sent to the authenticating user.
        /// </summary>
        /// <param name="count">Specifies the number of records to retrieve (must be between 1 and 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetDirectMessages(byte count)
        {
            if (count > 200 || count < 1) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the 20 most recent direct messages sent to the authenticating user.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetDirectMessages(int page)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages.xml",
                                        true,
                                        new KeyValuePair<string, string>("page", page.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the <i>countPerPage</i> most recent direct messages sent to the authenticating user.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve (must be greater than 0)</param>
        /// <param name="countPerPage">Specifies the number of records to retrieve (must be between 1 and 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetDirectMessages(uint page, uint countPerPage)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            if (countPerPage > 200 || countPerPage < 1) throw new ArgumentOutOfRangeException("countPerPage");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the 20 most recent direct messages sent to the authenticating user.
        /// </summary>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetDirectMessages(ulong sinceId)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the <i>count</i> most recent direct messages sent to the authenticating user.
        /// </summary>
        /// <param name="count">Specifies the page of results to retrieve (must be greater than 0)</param>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetDirectMessages(byte count, ulong sinceId)
        {
            if (count > 200 || count < 1) throw new ArgumentOutOfRangeException("count");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return new Collection<DirectMessage>(doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the 20 most recent direct messages sent to the authenticating user.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve (must be greater than 0)</param>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetDirectMessages(int page, ulong sinceId)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages.xml",
                                        true,
                                        new KeyValuePair<string, string>("page", page.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the <i>countPerPage</i> most recent direct messages sent to the authenticating user.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve (must be greater than 0)</param>
        /// <param name="countPerPage">Specifies the number of records to retrieve (must be between 1 and 200)</param>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetDirectMessages(uint page, uint countPerPage, ulong sinceId)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            if (countPerPage > 200 || countPerPage < 1) throw new ArgumentOutOfRangeException("countPerPage");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        } 
        #endregion

        #region GetSentDirectMessages
        /// <summary>
        /// Returns the 20 most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetSentDirectMessages()
        {
            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages/sent.xml",
                                        true);

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the <i>count</i> most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <param name="count">Specifies the number of records to retrieve (must be between 1 and 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetSentDirectMessages(byte count)
        {
            if (count < 1) throw new ArgumentOutOfRangeException("count");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages/sent.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the 20 most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve (must be greated than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetSentDirectMessages(int page)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages/sent.xml",
                                        true,
                                        new KeyValuePair<string, string>("page", page.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the <i>countPerPage</i> most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve (must be greater than 0)</param>
        /// <param name="countPerPage">Specifies the number of records to retrieve (must be between 1 and 200)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetSentDirectMessages(int page, int countPerPage)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            if (countPerPage > 200 || countPerPage < 1) throw new ArgumentOutOfRangeException("countPerPage");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages/sent.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the 20 most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetSentDirectMessages(ulong sinceId)
        {
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages/sent.xml",
                                        true,
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the <i>count</i> most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <param name="count">Specifies the page of results to retrieve (must be between 1 and 200)</param>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetSentDirectMessages(byte count, ulong sinceId)
        {
            if (count > 200 || count < 1) throw new ArgumentOutOfRangeException("count");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages/sent.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", count.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the 20 most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve (must be greater than 0)</param>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetSentDirectMessages(int page, ulong sinceId)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages/sent.xml",
                                        true,
                                        new KeyValuePair<string, string>("page", page.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return
                new Collection<DirectMessage>(
                    doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        }

        /// <summary>
        /// Returns the <i>countPerPage</i> most recent direct messages sent by the authenticating user.
        /// </summary>
        /// <param name="page">Specifies the page of results to retrieve (must be greater than 1)</param>
        /// <param name="countPerPage">Specifies the number of records to retrieve (must be between 1 and 200)</param>
        /// <param name="sinceId">Returns results with an ID greater than (that is, more recent than) the specified ID (must be greater than 0)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>List of direct messages</returns>
        public Collection<DirectMessage> GetSentDirectMessages(uint page, uint countPerPage, ulong sinceId)
        {
            if (page < 1) throw new ArgumentOutOfRangeException("page");
            if (countPerPage > 200 || countPerPage < 1) throw new ArgumentOutOfRangeException("countPerPage");
            if (sinceId < 1) throw new ArgumentOutOfRangeException("sinceId");

            var result = SendRequest(RequestMethod.Get,
                                        "https://api.twitter.com/1/direct_messages/sent.xml",
                                        true,
                                        new KeyValuePair<string, string>("count", countPerPage.ToString()),
                                        new KeyValuePair<string, string>("page", page.ToString()),
                                        new KeyValuePair<string, string>("since_id", sinceId.ToString()));

            var doc = XDocument.Parse(result);

            // ReSharper disable PossibleNullReferenceException
            return new Collection<DirectMessage>(doc.Element("direct-messages").Elements("direct_message").Select(ParseDirectMessage).ToList());
            // ReSharper restore PossibleNullReferenceException
        } 
        #endregion

        #region SendDirectMessage
        /// <summary>
        /// Sends a new direct message to the specified user from the authenticating user.
        /// </summary>
        /// <param name="screenName">The screen name of the user who should receive the direct message</param>
        /// <param name="message">The text of your direct message (140 characters at most)</param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <returns>Sent direct message</returns>
        public DirectMessage SendDirectMessage(string screenName, string message)
        {
            if (string.IsNullOrEmpty(screenName)) throw new ArgumentNullException("screenName");
            if (string.IsNullOrEmpty(message)) throw new ArgumentNullException("message");

            message = message.Normalize(NormalizationForm.FormC);
            if (message.Length > 140) throw new ArgumentOutOfRangeException("message", "Message is too long");

            var result = SendRequest(RequestMethod.Post,
                                        "https://api.twitter.com/1/direct_messages/new.xml",
                                        false,
                                        new KeyValuePair<string, string>("screen_name", screenName),
                                        new KeyValuePair<string, string>("text", Globals.ProperUrlEscape(message)));

            var doc = XDocument.Parse(result);

            return ParseDirectMessage(doc.Element("direct_message"));
        }

        /// <summary>
        /// Sends a new direct message to the specified user from the authenticating user.
        /// </summary>
        /// <param name="userId">The ID of the user who should receive the direct message</param>
        /// <param name="message">The text of your direct message (140 characters at most)</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        /// <returns>Sent direct message</returns>
        public DirectMessage SendDirectMessage(ulong userId, string message)
        {
            if (userId < 1) throw new ArgumentOutOfRangeException("userId");
            if (string.IsNullOrEmpty(message)) throw new ArgumentNullException("message");

            message = message.Normalize(NormalizationForm.FormC);
            if (message.Length > 140) throw new ArgumentOutOfRangeException("message", "Message is too long");

            var result = SendRequest(RequestMethod.Post,
                                        "https://api.twitter.com/1/direct_messages/new.xml",
                                        false,
                                        new KeyValuePair<string, string>("user_id", userId.ToString()),
                                        new KeyValuePair<string, string>("text", Globals.ProperUrlEscape(message)));

            var doc = XDocument.Parse(result);

            return ParseDirectMessage(doc.Element("direct_message"));
        }

        /// <summary>
        /// Sends a new direct message to the specified user from the authenticating user.
        /// </summary>
        /// <param name="user">The user who should receive the direct message</param>
        /// <param name="message">The text of your direct message (140 characters at most)</param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <returns>Sent direct message</returns>
        public DirectMessage SendDirectMessage(TwitterUser user, string message)
        {
            if (user == null) throw new ArgumentNullException("user");

            return SendDirectMessage(user.ScreenName, message);
        } 
        #endregion

        #region DeleteDirectMessage
        /// <summary>
        /// Destroys the specified direct message (the authenticating user must be the recipient of the specified direct message).
        /// </summary>
        /// <param name="messageId">The ID of the direct message to delete</param>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public void DeleteDirectMessage(ulong messageId)
        {
            if (messageId < 1) throw new ArgumentOutOfRangeException("messageId");

            SendRequest(RequestMethod.Delete,
                        string.Format("https://api.twitter.com/1/direct_messages/destroy/{0}.xml", messageId),
                        false);
        }

        /// <summary>
        /// Destroys the specified direct message (the authenticating user must be the recipient of the specified direct message).
        /// </summary>
        /// <param name="message">Message to delete</param>
        /// <exception cref="ArgumentNullException"></exception>
        public void DeleteDirectMessage(DirectMessage message)
        {
            if (message == null) throw new ArgumentNullException("message");
            SendRequest(RequestMethod.Delete,
                        string.Format("https://api.twitter.com/1/direct_messages/destroy/{0}.xml", message.Id),
                        false);
        } 
        #endregion

        /// <summary>
        /// Returns a single direct message, specified by an id parameter.
        /// </summary>
        /// <param name="messageId">ID of the direct message to return</param>
        /// <returns>Direct message</returns>
        /// <exception cref="ArgumentOutOfRangeException"><c>messageId</c> is out of range.</exception>
        public DirectMessage ShowDirectMessage(ulong messageId)
        {
            if (messageId < 1) throw new ArgumentOutOfRangeException("messageId");

            var response = SendRequest(RequestMethod.Get,
                        string.Format("https://api.twitter.com/1/direct_messages/show/{0}.xml", messageId),
                        true);

            var doc = XDocument.Parse(response);

            return ParseDirectMessage(doc.Element("direct_message"));
        }

        #endregion

        private static DirectMessage ParseDirectMessage(XElement dmElement)
        {
            DirectMessage directMessage = null;
            if (dmElement != null)
            {
                // ReSharper disable PossibleNullReferenceException
                directMessage = new DirectMessage(ulong.Parse(dmElement.Element("id").Value), ulong.Parse(dmElement.Element("sender_id").Value), dmElement.Element("text").Value, ulong.Parse(dmElement.Element("recipient_id").Value), ParseTiwtterTime(dmElement.Element("created_at").Value), dmElement.Element("sender_screen_name").Value, dmElement.Element("recipient_screen_name").Value, ParseAuthor(dmElement.Element("sender")), ParseAuthor(dmElement.Element("recipient")));
                return directMessage;
                // ReSharper restore PossibleNullReferenceException
            }
            return directMessage;
        }
    }
}
